home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / libs / stk110 / spredsrc.com / SPRED.C next >
C/C++ Source or Header  |  1991-02-25  |  16KB  |  467 lines

  1. /**********************************************************************
  2. * spred.c
  3. * The sprite editor for the Sprite support system, main module.  
  4. **********************************************************************
  5.                     This file is part of
  6.  
  7.          STK -- The sprite toolkit -- version 1.1
  8.  
  9.               Copyright (C) Jari Karjala 1991
  10.  
  11. The sprite toolkit (STK) is a FreeWare toolkit for creating high
  12. resolution sprite graphics with PCompatible hardware. This toolkit 
  13. is provided as is without any warranty or such thing. See the file
  14. COPYING for further information.
  15.  
  16. **********************************************************************/
  17.  
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include <stdarg.h>
  22. #include <ctype.h>
  23. #include <math.h>
  24. #include <graphics.h>
  25.  
  26. #include "grtypes.h"
  27. #include "gr.h"
  28. #include "mouse.h"
  29.  
  30. #include "spred.h"
  31. #include "spredio.h"
  32. #include "spredfio.h"
  33.  
  34. #define TRUE 1
  35. #define FALSE 0
  36. #define FILE_EXTENSION ".smp"
  37.  
  38. /**********************************************************************
  39. *  Temporary map for various transformations
  40. **********************************************************************/
  41. SPRED_MAP temp_map;
  42.  
  43. /**********************************************************************
  44. * The user supplied width, height of the sprite
  45. **********************************************************************/
  46. int width=0, height=0;
  47.  
  48. /**********************************************************************
  49. * FATAL ERROR: Close graphics, print error and exit.
  50. **********************************************************************/
  51. void error(char *s,...)
  52. {
  53.     char buf[100];
  54.     va_list argptr;
  55.  
  56.     va_start(argptr,s);
  57.     vsprintf(buf,s,argptr);
  58.     va_end(argptr);
  59.     
  60.     closegraph();
  61.     fputs(buf, stderr);
  62.     exit(10);
  63. }
  64.  
  65. /**********************************************************************
  66. * Prints explanation for the error code returned by the sprite file IO
  67. * Return: the parameter e
  68. **********************************************************************/
  69. int file_error(int e, char *filename)
  70. {
  71.     static char *msgs[] = {
  72.         "Error in closing file %s",
  73.         "Sprite file is not complete",
  74.         "Cannot find file %s",
  75.         ""
  76.     };
  77.  
  78.     message(msgs[3+e], filename);
  79.     return e;
  80. }
  81.  
  82. /**********************************************************************
  83. * Inverts the givent sprite's active bitmap
  84. **********************************************************************/
  85. void invert(SPRED_DATA *sdp)
  86. {
  87.     int i,j;
  88.     
  89.     for(i=0; i<sdp->w; i++)
  90.         for(j=0; j<sdp->h; j++)
  91.             if (sdp->maps[sdp->map][i][j] == DOT_FOREGROUND)
  92.                 sdp->maps[sdp->map][i][j] = DOT_BACKGROUND;
  93.             else
  94.                 sdp->maps[sdp->map][i][j] = DOT_FOREGROUND;
  95. }
  96.  
  97. /**********************************************************************
  98. * Rotate the given sprites active bitmap 90 degrees anticlockwise
  99. **********************************************************************/
  100. void rotate_90(SPRED_DATA *sdp)
  101. {
  102.     int i,j, lim, tmp;
  103.     
  104.     if (sdp->w > sdp->h)
  105.         lim = sdp->h-1;
  106.     else
  107.         lim = sdp->w-1;
  108.     
  109.     for(i=0; i<(lim+1)/2; i++)
  110.         for(j=0; j<(lim+1)/2; j++) {
  111.             tmp = sdp->maps[sdp->map][i][j];
  112.             
  113.             sdp->maps[sdp->map][i][j]
  114.                 = sdp->maps[sdp->map][lim - j][i];
  115.             
  116.             sdp->maps[sdp->map][lim - j][i]
  117.                 = sdp->maps[sdp->map][lim - i][lim - j];
  118.             
  119.             sdp->maps[sdp->map][lim - i][lim - j]
  120.                 = sdp->maps[sdp->map][j][lim - i];
  121.             
  122.             sdp->maps[sdp->map][j][lim - i]
  123.                 = tmp;
  124.         }
  125. }
  126.  
  127. /**********************************************************************
  128. * Rotate the active map 'angle' degrees anticlockwise.
  129. * The transformation is done in reverse order, ie the points in the
  130. * destination bitmap are projected into the source bitmap. This
  131. * usually produces better rotations.
  132. * NOTE: uses the global temp_map
  133. **********************************************************************/
  134. void rotate(SPRED_DATA *sdp, double angle)
  135. {
  136.     int i,j, i1,j1;
  137.     double s,c,xo,yo;
  138.     
  139.     angle = M_PI*angle/180;
  140.     s = sin(angle);
  141.     c = cos(angle);
  142.     xo = (sdp->w - 1)/2.0;
  143.     yo = (sdp->h - 1)/2.0;
  144.     for(i=0; i < sdp->w; i++)
  145.         for(j=0; j < sdp->h; j++) {
  146.             i1 = (c*(i - xo) - s*(j - yo)) + xo;
  147.             j1 = (s*(i - xo) + c*(j - yo)) + yo;
  148.             if (i1>=0 && i1<sdp->w && j1>=0 && j1<sdp->h)
  149.                 temp_map[i][j] = sdp->maps[sdp->map][i1][j1];
  150.             else
  151.                 temp_map[i][j] = DOT_BACKGROUND;
  152.         }
  153.     memcpy(sdp->maps[sdp->map], temp_map, sizeof(temp_map));
  154. }
  155.  
  156. /**********************************************************************
  157. * Make part of the given sprite's active map fatter.
  158. * If a point's color is 'mid' and it has a neighbour which is in color
  159. * 'border', then the point's color is changed to 'border'.
  160. * NOTE: uses the global temp_map
  161. **********************************************************************/
  162. void make_fatter(SPRED_DATA *sdp, int mid, int border)
  163. {
  164.     int i,j;
  165.     
  166.     for(i=0; i < sdp->w; i++)
  167.         for(j=0; j < sdp->h; j++) {
  168.             if (   sdp->maps[sdp->map][i][j]==mid
  169.                 && (  (i > 0 && sdp->maps[sdp->map][i-1][j]==border)
  170.                     ||(j > 0 && sdp->maps[sdp->map][i][j-1]==border)
  171.                     ||(i < sdp->w-1 && sdp->maps[sdp->map][i+1][j]==border)
  172.                     ||(j < sdp->h-1 && sdp->maps[sdp->map][i][j+1]==border)))
  173.                         temp_map[i][j] = border;
  174.                     else
  175.                         temp_map[i][j] = sdp->maps[sdp->map][i][j];
  176.         }
  177.     memcpy(sdp->maps[sdp->map], temp_map, sizeof(temp_map));
  178. }
  179.  
  180.  
  181. /**********************************************************************
  182. * Load the sprite from the given file. If filename is a null string,
  183. * then the sdp->name is used.
  184. **********************************************************************/
  185. void load(SPRED_DATA *sdp, char *filename)
  186. {
  187.     sdp->w = width;
  188.     sdp->h = height;
  189.     if (filename[0]!='\0')
  190.         strcpy(sdp->name, filename);
  191.     if (strrchr(sdp->name, '.')==NULL)
  192.         strcat(sdp->name, FILE_EXTENSION);
  193.     message("Loading %s", sdp->name);
  194.     if (file_error(load_sprite(sdp), sdp->name)==0)
  195.         message("File: %s  Size: %dx%d", sdp->name, sdp->w, sdp->h);
  196.     else if ((sdp->w | sdp->h) == 0) {
  197.         sdp->w = 32;
  198.         sdp->h = 24;
  199.     }
  200.     draw_screen(sdp);
  201. }
  202.  
  203. /**********************************************************************
  204. * Edit the given sprite. The screen must be in graphics mode and
  205. * the mouse interface must be functional.
  206. * Return: 0 if normal exit with save, negative if quit
  207. **********************************************************************/
  208. int spred_edit(SPRED_DATA *sdp, int filec, char **filev)
  209. {
  210.     char buf[SPR_NAME_LEN];
  211.     MSG msg;
  212.     int x,y, ox, oy, i,j, tmp, quit, curfile;
  213.     static double angle = 30.0;
  214.  
  215.     sdp->map = SPR_SHAPE;
  216.  
  217.     curfile = 0;
  218.     load(sdp, filev[curfile]);
  219.     
  220.     quit = FALSE;
  221.     ox = oy = -1;
  222.     while (!quit) {
  223.         msg=get_msg(sdp, &x,&y);
  224.         switch (msg) {
  225.             case MSG_QUIT:
  226.                 quit = TRUE;
  227.                 break;
  228.                 
  229.             case MSG_EXIT:
  230.                 if (file_error(save_sprite(sdp), sdp->name)==0)
  231.                     quit = TRUE;
  232.                 break;
  233.  
  234.             case MSG_SAVE:
  235.                 message("Give the save filename [%s]:", sdp->name);
  236.                 if (gr_gets(buf, SPR_NAME_LEN)!=NULL) {
  237.                     if (buf[0]!='\0')
  238.                         strcpy(sdp->name, buf);
  239.                     if (strrchr(sdp->name, '.')==NULL)
  240.                         strcat(sdp->name, FILE_EXTENSION);
  241.                     message("Saving %s", sdp->name);
  242.                     file_error(save_sprite(sdp), sdp->name);
  243.                 }
  244.                 else
  245.                     message("");
  246.                 break;
  247.                 
  248.             case MSG_LOAD:
  249.                 message("Give the load filename [%s]:", sdp->name);
  250.                 if (gr_gets(buf, SPR_NAME_LEN)!=NULL)
  251.                     load(sdp, buf);
  252.                 else
  253.                     message("");
  254.                 break;
  255.                 
  256.             case MSG_NEXT:
  257.                 if (curfile+1 < filec)
  258.                     load(sdp, filev[++curfile]);
  259.                 else
  260.                     message("No more sprites");
  261.                 break;
  262.                 
  263.             case MSG_PREV:
  264.                 if (curfile > 0)
  265.                     load(sdp, filev[--curfile]);
  266.                 else
  267.                     message("No previous sprites");
  268.                 break;
  269.                 
  270.             case MSG_CLEAR:
  271.                 memset(sdp->maps[sdp->map], DOT_BACKGROUND,sizeof(SPRED_MAP));
  272.                 draw_map(sdp, sdp->map);
  273.                 break;
  274.                 
  275.             case MSG_COPY_TO_SHAPE:
  276.                 memcpy(sdp->maps[SPR_SHAPE], sdp->maps[SPR_MASK], 
  277.                        sizeof(sdp->maps[sdp->map]));
  278.                 sdp->map = SPR_SHAPE;
  279.                 invert(sdp);
  280.                 draw_map(sdp, SPR_SHAPE);
  281.                 break;
  282.                 
  283.             case MSG_COPY_TO_MASK:
  284.                 memcpy(sdp->maps[SPR_MASK], sdp->maps[SPR_SHAPE], 
  285.                        sizeof(sdp->maps[sdp->map]));
  286.                 sdp->map = SPR_MASK;
  287.                 invert(sdp);
  288.                 draw_map(sdp, SPR_MASK);
  289.                 break;
  290.                 
  291.             case MSG_ACTIVATE_MASK:
  292.                 sdp->map = SPR_MASK;
  293.                 draw_map(sdp, sdp->map);
  294.                 break;
  295.                 
  296.             case MSG_ACTIVATE_SHAPE:
  297.                 sdp->map = SPR_SHAPE;
  298.                 draw_map(sdp, sdp->map);
  299.                 break;
  300.  
  301.             /***** Point drawing functions *****/
  302.             case MSG_BTN1_CLICK:    /** set point **/
  303.                 sdp->maps[sdp->map][x][y] = DOT_FOREGROUND;
  304.                 draw_point(sdp, x, y, sdp->map);
  305.                 message("Last point: X=%d Y=%d", x,y);
  306.                 break;
  307.                 
  308.             case MSG_BTN2_CLICK:    /** flip point **/
  309.                 if (x!=ox || y!=oy) {
  310.                     if (sdp->maps[sdp->map][x][y] == DOT_FOREGROUND)
  311.                         sdp->maps[sdp->map][x][y] = DOT_BACKGROUND;
  312.                     else
  313.                         sdp->maps[sdp->map][x][y] = DOT_FOREGROUND;
  314.                     draw_point(sdp, x, y, sdp->map);
  315.                 }
  316.                 message("Last point: X=%d Y=%d", x,y);
  317.                 break;
  318.                 
  319.             case MSG_BTN3_CLICK:    /** clear point **/
  320.                 sdp->maps[sdp->map][x][y] = DOT_BACKGROUND;
  321.                 draw_point(sdp, x, y, sdp->map);
  322.                 message("Last point: X=%d Y=%d", x,y);
  323.                 break;
  324.  
  325.  
  326.             /***** Image manipulation commands *****/
  327.             case MSG_INVERT:
  328.                 invert(sdp);
  329.                 draw_map(sdp, sdp->map);
  330.                 break;
  331.  
  332.             case MSG_OVERLAY:
  333.                 draw_map(sdp, sdp->map | DOT_OVERLAY);
  334.                 break;
  335.  
  336.             case MSG_ROTATE90:
  337.                 rotate_90(sdp);
  338.                 draw_map(sdp, sdp->map);
  339.                 break;
  340.  
  341.             case MSG_ROTATE:
  342.                 message("Give rotation angle [%.1lf]:", angle);
  343.                 if (gr_gets(buf, sizeof(buf))!=NULL) {
  344.                     if (buf[0]!='\0')
  345.                         angle = atof(buf);
  346.                     rotate(sdp, angle);
  347.                     draw_map(sdp, sdp->map);
  348.                 }
  349.                 message("");                
  350.                 break;
  351.  
  352.             case MSG_HFLIP:
  353.                 for(i=0; i<sdp->w/2; i++)
  354.                     for(j=0; j<sdp->h; j++) {
  355.                         tmp = sdp->maps[sdp->map][sdp->w - i - 1][j];
  356.                         sdp->maps[sdp->map][sdp->w - i - 1][j]
  357.                             = sdp->maps[sdp->map][i][j];
  358.                         sdp->maps[sdp->map][i][j] = tmp;
  359.                     }
  360.                 draw_map(sdp, sdp->map);
  361.                 break;
  362.                 
  363.             case MSG_VFLIP:
  364.                 for(i=0; i<sdp->w; i++)
  365.                     for(j=0; j<sdp->h/2; j++) {
  366.                         tmp = sdp->maps[sdp->map][i][sdp->h - j - 1];
  367.                         sdp->maps[sdp->map][i][sdp->h - j - 1]
  368.                             = sdp->maps[sdp->map][i][j];
  369.                         sdp->maps[sdp->map][i][j] = tmp;
  370.                     }
  371.                 draw_map(sdp, sdp->map);
  372.                 break;
  373.                 
  374.             case MSG_HMIRROR:
  375.                 for(i=0; i<sdp->w/2; i++)
  376.                     for(j=0; j<sdp->h; j++) {
  377.                         tmp = sdp->maps[sdp->map][sdp->w - i - 1][j];
  378.                         if (sdp->maps[sdp->map][i][j]==DOT_FOREGROUND)
  379.                             sdp->maps[sdp->map][sdp->w - i - 1][j]
  380.                                 = sdp->maps[sdp->map][i][j];
  381.                         if (tmp==DOT_FOREGROUND)
  382.                             sdp->maps[sdp->map][i][j] = tmp;
  383.                     }
  384.                 draw_map(sdp, sdp->map);
  385.                 break;
  386.                 
  387.             case MSG_VMIRROR:
  388.                 for(i=0; i<sdp->w; i++)
  389.                     for(j=0; j<sdp->h/2; j++) {
  390.                         tmp = sdp->maps[sdp->map][i][sdp->h - j - 1];
  391.                         if (sdp->maps[sdp->map][i][j]==DOT_FOREGROUND)
  392.                             sdp->maps[sdp->map][i][sdp->h - j - 1]
  393.                                 = sdp->maps[sdp->map][i][j];
  394.                         if (tmp==DOT_FOREGROUND)
  395.                             sdp->maps[sdp->map][i][j] = tmp;
  396.                     }
  397.                 draw_map(sdp, sdp->map);
  398.                 break;                
  399.                 
  400.             case MSG_FATTER:
  401.                 make_fatter(sdp, DOT_BACKGROUND, DOT_FOREGROUND);
  402.                 draw_map(sdp, sdp->map);
  403.                 break;
  404.  
  405.             case MSG_THINNER:
  406.                 make_fatter(sdp, DOT_FOREGROUND, DOT_BACKGROUND);
  407.                 draw_map(sdp, sdp->map);
  408.                 break;
  409.  
  410.             case MSG_NONE:
  411.                 break;
  412.                 
  413.             default:
  414.                 message("Message %d not implemented", msg, x, y);
  415.         }
  416.         ox = x;
  417.         oy = y;
  418.     }
  419.     
  420.     return -(msg == MSG_QUIT);
  421. }
  422.  
  423.  
  424. /**********************************************************************
  425. * The sprite to be edited. Must be global, since the structure
  426. * take about 20 kBytes. It is automatically initialized to zero.
  427. **********************************************************************/
  428. SPRED_DATA sd;
  429.  
  430. void main(int argc, char **argv)
  431. {
  432.     int i,j;
  433.     
  434.     puts("SPRED -- Sprite editor v1.1 -- Copyright (C) 1991 Jari Karjala");
  435.     
  436.     if (argc<2 || (argc==2 && argv[1][0]=='-'))
  437.         error("\nUSAGE: SPRED [-WxH] sprite[.ext] [...]\n");
  438.  
  439.     /** get size if given **/
  440.     if (argc>2 && argv[1][0]=='-') {
  441.         if (sscanf(&argv[1][1], "%dx%d", &width, &height)!=2)
  442.             error("Illegal width/height format, use WxH, eg 32x24");
  443.         if (width > MAX_SPRITE_WIDTH || height > MAX_SPRITE_HEIGHT)
  444.             error("Sprite too large, max size %dx%d", 
  445.                     MAX_SPRITE_WIDTH, MAX_SPRITE_HEIGHT);
  446.         argc--;
  447.         argv++;
  448.     }
  449.     
  450.     gr_detect(GR_TYPE_SPR, &i, &j);
  451.     if (i == -1) {
  452.         puts("Unsupported graphics mode, sorry!");
  453.         exit(1);
  454.     }
  455.     gr_start(&i, &j);
  456.     if (mouse_initialize()==0)
  457.         error("No mouse driver found, cannot continue");
  458.     mouse_set_pointer_xy(gr_max_x/2, 3*gr_max_y/4);
  459.     
  460.     if (spred_edit(&sd, argc-1, argv+1) < 0)
  461.         exit(1);    /** some error, or quit **/
  462.  
  463.     exit(0);
  464. }
  465.